package br.ufc.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import br.ufc.parser.*;

public class QueriesLoad {

	private Collection<CustomStatement> statements;
	private List<String> dimensions;
	private Map<String, Value> maxs;
	private Map<String, Value> mins;

	public QueriesLoad(Collection<CustomStatement> statements,
			List<String> dimensions, Map<String, Value> maxs,
			Map<String, Value> mins) {
		super();
		this.statements = statements;
		this.dimensions = dimensions;
		this.maxs = maxs;
		this.mins = mins;
	}

	public Collection<CustomStatement> getStatements() {
		return statements;
	}

	public void setStatements(Collection<CustomStatement> statements) {
		this.statements = statements;
	}

	public List<String> getDimensions() {
		return dimensions;
	}

	public void setDimensions(List<String> dimensions) {
		this.dimensions = dimensions;
	}

	public Map<String, Value> getMaxs() {
		return maxs;
	}

	public Map<String, Value> getMins() {
		return mins;
	}

	static final Comparator<Predicate> VALUE_ORDER = 
			new Comparator<Predicate>() {
		public int compare(Predicate p1, Predicate p2) {
			return p1.getValue().compareTo(p2.getValue());
		}
	};

	public List<Value> getCuts(String dimension, int divisions){
		List<Predicate> predicates = new ArrayList<Predicate>();
		for(CustomStatement statement : statements){
			if(statement.isSelect()){
				Query query = statement.getSelect();
				for(Predicate predicate : query.getPredicates()){
					if(predicate.getAttribute().equals(dimension)){
						predicates.add(predicate);
					}
				}
			}
		}	
		List<Value> cuts = new ArrayList<Value>();
		Collections.sort(predicates, VALUE_ORDER);
		cuts.add(predicates.get(0).getValue());
		List<Predicate> predicatesCopy = predicates;
		for(int i = 1; i < divisions; i ++){
			Value lastCut = cuts.get(i-1); 
			for(int j = 0; j < predicatesCopy.size(); j++){				
				if(predicatesCopy.get(j).getValue().compareTo(lastCut) > 0){
					predicatesCopy = predicatesCopy.subList(j, predicatesCopy.size());
					break;
				}
				if(j == predicatesCopy.size() - 1){
					throw new RuntimeException("Should not happen");
				}
			}			
			int diff = Integer.MAX_VALUE;
			int leftFinal = 0, rightFinal = 0, indexFinal = 0;
			for(int j = 0; j < predicatesCopy.size(); j ++){
				Predicate predicate = predicatesCopy.get(j);
				List<Integer> weights;
				weights = computeWeights(predicatesCopy, predicate.getValue());
				int left = weights.get(0)*(divisions - i);
				int right = weights.get(1);
				if(Math.abs(left - right) < diff){
					leftFinal = left;
					rightFinal = right;
					indexFinal = j;
					diff = Math.abs(left - right); 
				}
			}
			cuts.add(predicatesCopy.get(indexFinal).getValue());
			System.out.println(leftFinal/(divisions - i) + " " + rightFinal);
		}
		cuts.add(predicates.get(predicates.size()-1).getValue());
//		for(Value cut : cuts){			
//			System.out.println(cut + " " + computeWeights(predicates, cut).get(0) + " " + computeWeights(predicates, cut).get(1));			
//		}
		return cuts;
	}
	
	private List<Integer> computeWeights(List<Predicate> predicates, Value cut){
		int left = 0;
		int right = 0;
		for(Predicate predicate : predicates){
			if(predicate.getOperation().equals(">")){
				Value value = predicate.getValue();
				if(value.compareTo(cut) < 0){
					left ++;
				}
				right ++;
			}
			if(predicate.getOperation().equals("<")){
				Value value = predicate.getValue();
				if(value.compareTo(cut) > 0){
					right ++;
				}
				left ++;
			}
			if(predicate.getOperation().equals("=")){
				Value value = predicate.getValue();
				if(value.compareTo(cut) < 0){
					left ++;
				}else{
					right ++;
				}
			}
		}
		return Arrays.asList(left, right);
	}
}